import { ref, onBeforeUnmount } from "vue";
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
import nunjucks from 'nunjucks';
import { pickBy, omit } from 'lodash-es';
import type { ComponentType, AnyObject } from "@/materials/index.d";
import * as prettier from 'prettier/standalone';
import prettierPluginBabel from 'prettier/plugins/babel';
import prettierPluginEstree from 'prettier/plugins/estree';
import prettierPluginHtml from 'prettier/plugins/html';

export const useCodeEditor = (options: monaco.editor.IStandaloneEditorConstructionOptions = {}) => {

    const el = ref();

    let editor: monaco.editor.IStandaloneCodeEditor;

    const createEditor = () => {
        editor = monaco.editor.create(el.value, {
            language: "typescript",
            automaticLayout: true,
           // readOnly: true,
            minimap: {enabled: false},
            //theme: "vs-dark",
            ...options
        });
        return editor;
    };

    const updateEditorValue = async (value: string) => {
        editor.setValue(value);
    };

    const getEditorValue = () => {
        return editor.getValue();
    };

    onBeforeUnmount(()=>{
        editor.dispose();
    });

    return {
        el,
        createEditor,
        updateEditorValue,
        getEditorValue
    }
};

export const useCompileCode = () => {
    const tplItem = `<{{ package }} 
{% for key, value in filterEmpty(omitProps(props)) %}
  {{ addColon(value) }}{{ key }} = "{{ value }}"
{% endfor %}

:style="{
    {% for key, value in filterEmpty(styles) %}
      {{ key }}: '{{ value }}',
    {% endfor %}
}"
>
   {{ props.slot }}
</{{ package }}>`;

const tplList = `<template>
    {% for component in componentList %}
        <{{ component.package }}
        {% for key, value in filterEmpty(omitProps(component.props)) %}
  {{ addColon(value) }}{{ key }} = "{{ value }}"
{% endfor %}

:style="{
    {% for key, value in filterEmpty(component.styles) %}
      {{ key }}: '{{ value }}',
    {% endfor %}
}"
>
   {{ component.props.slot }}
</{{ component.package }}> 
    {% endfor %}
</template>
<script lang="ts" setup>
   {% for component in componentList %}import {{ component.package }} from '@/components/{{ component.package }}/index.vue'; 
   {% endfor %}
</script>`;

const addColon = (val: any) => {
    return typeof val === "string" ? "" : ":";
}
const filterEmpty = (data: AnyObject) => {
    return pickBy(data, (value)=> value !== "");
}
const omitProps = (data: AnyObject) => {
    return omit(data, ["slot"]);
}
const renderString = (data: ComponentType) => {
  return nunjucks.renderString(tplItem, {
    ...data,
    addColon,
    filterEmpty,
    omitProps
    });
 };

 const renderListString = (data: ComponentType) => {
    return nunjucks.renderString(tplList, {
      ...data,
      addColon,
      filterEmpty,
      omitProps
      });
   };

 const formatCode = (code: string) => {
    return prettier.format(code, {
       parser: "vue",
       plugins: [prettierPluginBabel, prettierPluginEstree, prettierPluginHtml]
     });
 }

 const compileCode = (data: ComponentType, type = 'item') => {
    const render = type === "item" ? renderString : renderListString;
    const code = render(data);
    return formatCode(code);
 }

 return {
    compileCode
 }

}

export type EditorOptions = monaco.editor.IStandaloneEditorConstructionOptions